package cn.s1995.sloth.bizs.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.StrUtil;
import cn.s1995.sloth.common.core.constant.enums.hint.Hint;
import cn.s1995.sloth.bizs.entity.Prod;
import cn.s1995.sloth.bizs.entity.ProdCategory;
import cn.s1995.sloth.bizs.mapper.ProdCategoryMapper;
import cn.s1995.sloth.bizs.mapper.ProdMapper;
import cn.s1995.sloth.bizs.service.ProdCategoryService;
import cn.s1995.sloth.common.core.constant.CommonConstants;
import cn.s1995.sloth.common.core.util.R;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 产品分类
 *
 * @author Lex
 * @date 2023-12-14 09:47:11
 */
@Service
public class ProdCategoryServiceImpl extends ServiceImpl<ProdCategoryMapper, ProdCategory> implements ProdCategoryService {

    @Resource
    private ProdMapper prodMapper;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean saveCategory(ProdCategory prodCategory) {
        boolean save = this.save(prodCategory);
        // 赋值path
        prodCategory.setPath(this.buildCategoryPath(prodCategory));

        boolean update = this.updateById(prodCategory);
        return save && update;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateCategory(ProdCategory prodCategory) {
        // 赋值path
        prodCategory.setPath(this.buildCategoryPath(prodCategory));
        return this.updateById(prodCategory);
    }

    @Override
    public R removeBatchCategory(Long[] ids) {
        if (ArrayUtil.isEmpty(ids)) {
            return R.ok();
        }
        LambdaQueryWrapper<ProdCategory> prodCategoryLambdaQueryWrapper = Wrappers.lambdaQuery(ProdCategory.class);
        LambdaQueryWrapper<Prod> prodLambdaQueryWrapper = Wrappers.lambdaQuery(Prod.class);
        for (Long id : ids) {
            prodCategoryLambdaQueryWrapper.or().like(ProdCategory::getPath, id);
            prodLambdaQueryWrapper.or().like(Prod::getCategoryPath, id);
        }

        Long prodCount = this.count(prodCategoryLambdaQueryWrapper);
        if (prodCount <= 0) {
            return R.failed(Hint.BMS_PROD_CATEGORY_NOT_EXISTS);
        }
        // 分类存在子类或分类存在关联项目，则不能删除
        if (prodCount > 1) {
            return R.failed(Hint.BMS_PROD_CATEGORY_EXISTS_CHILD);
        }

        long count = prodMapper.selectCount(prodLambdaQueryWrapper);
        if (count > 0) {
            return R.failed(Hint.BMS_PROD_CATEGORY_EXISTS_PROJECT);
        }

        return R.ok(this.removeBatchByIds(Arrays.stream(ids).toList()));
    }

    @Override
    public List<Tree<Long>> treeMenu(Long pid, String name) {
        Long parent = pid == null ? CommonConstants.MENU_TREE_ROOT_ID : pid;

        List<TreeNode<Long>> collect = baseMapper
                .selectList(Wrappers.<ProdCategory>lambdaQuery()
                        .like(StrUtil.isNotBlank(name), ProdCategory::getName, name)
                        .orderByAsc(ProdCategory::getSort))
                .stream()
                .map(getNodeFunction())
                .collect(Collectors.toList());

        // 模糊查询 不组装树结构 直接返回 表格方便编辑
        if (StrUtil.isNotBlank(name)) {
            return collect.stream().map(node -> {
                Tree<Long> tree = new Tree<>();
                tree.putAll(node.getExtra());
                BeanUtils.copyProperties(node, tree);
                return tree;
            }).collect(Collectors.toList());
        }

        return TreeUtil.build(collect, parent);
    }

    @Override
    public String buildCategoryPath(ProdCategory ProdCategory) {
        String res;
        if (Objects.isNull(ProdCategory.getPid()) || ProdCategory.getPid() == CommonConstants.MENU_TREE_ROOT_ID) {
            res = String.format("%s,%s", CommonConstants.MENU_TREE_ROOT_ID, ProdCategory.getId());
        } else {
            ProdCategory parent = this.getById(ProdCategory.getPid());
            if (Objects.nonNull(parent)) {
                res = String.format("%s,%s", parent.getPath(), ProdCategory.getId());
            } else {
                res = String.format("%s,%s", CommonConstants.MENU_TREE_ROOT_ID, ProdCategory.getId());
            }
        }

        return res;
    }

    @Override
    public String buildCategoryPath(Long id) {
        return buildCategoryPath(this.getById(id));
    }

    @NotNull
    private Function<ProdCategory, TreeNode<Long>> getNodeFunction() {
        return item -> {
            TreeNode<Long> node = new TreeNode<>();
            node.setId(item.getId());
            node.setName(item.getName());
            node.setParentId(item.getPid());
            node.setWeight(item.getSort());
            // 扩展属性
            Map<String, Object> extra = new HashMap<>();
            extra.put("icon", item.getIcon());
            extra.put("isShow", item.getIsShow());
            extra.put("sort", item.getSort());
            extra.put("path", item.getPath());
            extra.put("pic", item.getPic());
            node.setExtra(extra);
            return node;
        };
    }

}
